/*
 * TextureImpl.h
 *
 *  Created on: 2011/07/06
 *      Author: naoki
 */

#ifndef INCLUDED_NTENGINE_GRAPHICS_TEXTUREIMPL_H
#define INCLUDED_NTENGINE_GRAPHICS_TEXTUREIMPL_H

#include "NTEngine/Graphics/Texture.h"
#include "NTEngine/FileIO/InFile.h"
#include "NTEngine/Base/ReferenceCounter.h"
#include "NTEngine/Base/Array.h"
#include "NTEngine/Base/DebugStream.h"
#include "NTEngine/Xml/Element.h"
#include "NTEngine/Xml/Attribute.h"
#include "NTEngine/Base/RefString.h"
#include <ctype.h>
#include <string.h>
#include <GLES2/gl2.h>

namespace NTEngine {
using namespace Xml;
namespace Graphics {
using namespace std;

/**
 * @brief テクスチャ実体
 */
class Texture::Impl : public ReferenceCounter {
public:
	enum Extension {
		EXT_UNKNOWN,
		EXT_DDS,
		EXT_TGA,
	};

	// -------
	Impl( ConstElement e, const char* path )
	: mObject( 0 )
	, mWidth( 0 )
	, mHeight( 0 )
	, mOriginalWidth( 0 )
	, mOriginalHeight( 0 )
	, mExtension( EXT_UNKNOWN )
	, mFile()
	, mIsError( true ) //一回エラー状態にしておく。成功すれば後でtrueにする
	, mName( 0 ) {
		//名前やらファイル名やらを抜く
		int an = e.attributeNumber();
		for ( int i = 0; i < an; ++i ){
			ConstAttribute a = e.attribute( i );
			RefString name( a.name() );
			if ( name == "name" ){
				RefString tmpName( a.value() );
				mName = tmpName.copyOriginal();
			}else if ( name == "filename" ){
				mExtension = getExtension( a.value() );
				if ( mExtension != EXT_UNKNOWN ){
					string filename = ( path ) ? path : "";
					if ( filename.size() > 0 ){
						char last = filename[ filename.size() - 1 ];
						if ( last != '\\' && last != '/' ){
							filename += '/';
						}
					}
					filename += a.value();
					mFile = FileIO::InFile::create( filename.c_str() );
					mIsError = false; //知ってる拡張子のファイルがあった
				}
			}
		}
	}

	Impl( const char* fileName )
	: mObject( 0 )
	, mWidth( 0 )
	, mHeight( 0 )
	, mOriginalWidth( 0 )
	, mOriginalHeight( 0 )
	, mFile()
	, mIsError( false )
	, mName( 0 ) {
		mExtension = getExtension( fileName );
		if ( mExtension != EXT_UNKNOWN ) {
			mFile = FileIO::InFile::create( fileName );
		} else {
			mIsError = true;
		}
	}

	Impl( GLint w, GLint h, bool createMipChain )
	: mObject( 0 )
	, mWidth( 0 )
	, mHeight( 0 )
	, mOriginalWidth( 0 )
	, mOriginalHeight( 0 )
	, mFile()
	, mIsError( false )
	, mName( 0 ) {
		createObject( w, h, createMipChain );
	}

	Impl( const char* data, int size )
	: mObject( 0 )
	, mWidth( 0 )
	, mHeight( 0 )
	, mOriginalWidth( 0 )
	, mOriginalHeight( 0 )
	, mFile()
	, mIsError( false )
	, mName( 0 ) {
		// ファイル名がなく判断できないので、中身4バイトで判定
		if ( data[ 0 ] == 'D' && data[ 1 ] == 'D' && data[ 2 ] == 'S' && data[ 3 ] == ' ' ){
			readDDS( data, size );
		} else { //tgaとして解釈
			readTGA( data, size );
		}
	}

	~Impl() {
		for ( int i = 0; i < mSurfaces.size(); ++i ) {
			mSurfaces[ i ].release();
		}
		SAFE_DELETE_ARRAY( mName );
		glDeleteTextures( 1, &mObject );
		mObject = 0;
	}

	int width() const {
		return mWidth;
	}

	int height() const {
		return mHeight;
	}

	int originalWidth() const {
		return mOriginalWidth;
	}

	int originalHeight() const {
		return mOriginalHeight;
	}

	const char* name() const {
		return mName;
	}

	bool hasMipmapChain() const {
		// 基本的にAll or Nothingなので1より多くサーフェイス用バッファがあれば完全なミップマップチェーンがあるとみなす
		return ( mSurfaces.size() > 1 );
	}

	void lock( unsigned** surface, int* pitch, int level ) {
		// ミップマップレベルのサイズを調べてそのサイズでロックする
		int w = mWidth >> level;
		int h = mHeight >> level;
		if ( w == 0 ) {
			w = 1;
		}
		if ( h == 0 ) {
			h = 1;
		}
		lock( surface, pitch, 0, 0, w, h, level );
	}

	void lock( unsigned** surface, int* pitch, int x, int y, int w, int h, int level ) {
		ASSERT( 0 <= level && level < mSurfaces.size() );
		ASSERT( mSurfaces[ level ].mBuffer == 0 );
#ifndef NDEBUG
		// デバッグ用チェック
		int dw = mWidth >> level;
		int dh = mHeight >> level;
		if ( dw == 0 ) {
			dw = 1;
		}
		if ( dh == 0 ) {
			dh = 1;
		}
		ASSERT( x + w <= dw );
		ASSERT( y + h <= dh );
#endif
		mSurfaces[ level ].set( x, y, w, h );
		// mipmaplevelの幅を返す。こればバイト単位。
		*pitch = w * 4; // * sizeof( unsigned )
		*surface = mSurfaces[ level ].mBuffer;
	}

	void unlock( int level ) {
		ASSERT( 0 <= level && level < mSurfaces.size() );
		ASSERT( mSurfaces[ level ].mBuffer );
		glBindTexture( GL_TEXTURE_2D, mObject );
		glTexSubImage2D( GL_TEXTURE_2D, level,
			mSurfaces[ level ].mX, mSurfaces[ level ].mY, mSurfaces[ level ].mW, mSurfaces[ level ].mH,
			GL_RGBA, GL_UNSIGNED_BYTE, mSurfaces[ level ].mBuffer );
		glBindTexture( GL_TEXTURE_2D, 0 );
		mSurfaces[ level ].release();
	}

	// TODO:テスト用。HWで完全ミップマップチェーンを生成させる。一部機種でエラーになるが。。
	void generateMipmapWithHardware() {
		glBindTexture( GL_TEXTURE_2D, mObject );
		glGenerateMipmap( GL_TEXTURE_2D );
		glBindTexture( GL_TEXTURE_2D, 0 );
	}

	bool isReady() {
		if ( mFile ) {
			if ( mFile.isFinished() ) {
				if ( mFile.isError() ) {
					mIsError = true;
				} else {
					if ( mExtension == EXT_DDS ) {
						readDDS( mFile.data(), mFile.size() );
					} else if ( mExtension == EXT_TGA ) {
						readTGA( mFile.data(), mFile.size() );
					} else {
						ASSERT( 0 );
					}
				}
				// ファイルは必要ないので開放する
				mFile.release();
			} else {
				return false;
			}
		}
		return true;
	}

	bool isError() const {
		return mIsError;
	}

//private:
	void readDDS( const char* data, int size ) {
		int sh = toUInt( data + 12 );
		int sw = toUInt( data + 16 );
		mOriginalWidth = sw;
		mOriginalHeight = sh;
		int pixelSize = toUInt( data + 88 ) / 8;
		//ファイルサイズ大丈夫？
		if ( size < ( sh * sw * pixelSize + 128 ) ){
			mIsError = true; //ファイルが壊れてる
			return;
		}
		//2べきに直してテクスチャ作成
		int dh = powOfTwo( sh );
		int dw = powOfTwo( sw );
		createObject( dw, dh, true );

		//ロックして書き込み
		unsigned* surface;
		int pitch;
		lock( &surface, &pitch, 0 );
		pitch /= 4;
		unsigned* dst = surface;
		const unsigned char* src = reinterpret_cast< const unsigned char* >( data );
		src += 128; //データ先頭取得

		if ( pixelSize == 4 ) {
			unsigned alphaMask = toUInt( data + 0x68 );
			unsigned alphaOr = ( alphaMask == 0 ) ? 0xff000000 : 0;
			for ( int y = 0; y < sh; ++y ) {
				for ( int x = 0; x < sw; ++x ) {
					dst[ x ] = src[ x * 4 + 0 ] << 16;
					dst[ x ] |= src[ x * 4 + 1 ] << 8;
					dst[ x ] |= src[ x * 4 + 2 ];
					dst[ x ] |= src[ x * 4 + 3 ] << 24;
					dst[ x ] |= alphaOr; //XRGB対応
				}
				for ( int x = sw; x < pitch / 4; ++x ){ //Xあまりは真っ黒
					dst[ x ] = 0;
				}
				dst += pitch;
				src += ( sw * pixelSize + 3 ) & ( ~3 ); //4バイトアライン
			}
		} else if ( pixelSize == 3 ) {
			for ( int y = 0; y < sh; ++y ) {
				for ( int x = 0; x < sw; ++x ) {
					dst[ x ] = src[ x * 3 + 0 ] << 16;
					dst[ x ] |= src[ x * 3 + 1 ] << 8;
					dst[ x ] |= src[ x * 3 + 2 ];
					dst[ x ] |= 0xff000000; //Aは255
				}
				for ( int x = sw; x < pitch; ++x ) { //Xあまりは真っ黒
					dst[ x ] = 0;
				}
				dst += pitch;
				src += ( sw * pixelSize + 3 ) & ( ~3 ); //4バイトアライン
			}
		} else if ( pixelSize == 1 ) {
			for ( int y = 0; y < sh; ++y ) {
				for ( int x = 0; x < sw; ++x ){
					dst[ x ] = 0x00ffffff;
					dst[ x ] |= src[ x ] << 24;
				}
				for ( int x = sw; x < pitch; ++x ) { //Xあまりは真っ黒
					dst[ x ] = 0;
				}
				dst += pitch;
				src += ( sw * pixelSize + 3 ) & ( ~3 ); //4バイトアライン
			}
		}
		//Yあまりを真っ黒に
		for ( int y = sh; y < dh; ++y  ){
			for ( int x = 0; x < pitch; ++x ) {
				dst[ x ] = 0;
			}
			dst += pitch;
		}
		createMipmapChain( surface, pitch, dw, dh, 1 );
		unlock( 0 );
		src = 0;
		dst = 0;
	}

	void readTGA( const char* data, int size ) {
		int sw = toUShort( data + 12 );
		int sh = toUShort( data + 14 );
		mOriginalWidth = sw;
		mOriginalHeight = sh;
		int pixelSize = toUChar( data + 16 ) / 8;
		int paletteNumber = 0;
		int paletteDepth = 0;
		//パレットあんの？
		if ( ( data[ 2 ] & 7 ) == 1 ){
			paletteNumber = toUShort( data + 5 );
			paletteDepth = toUChar( data + 7 ) / 8;
			ASSERT( paletteDepth == 3 || paletteDepth == 4 );
		}
		const unsigned char* src = 0;
		const unsigned char* pSrc = 0; //パレットデータ
		src = reinterpret_cast< const unsigned char* >( data );
		pSrc = src + 18;
		src += 18 + paletteNumber * paletteDepth; //データ先頭取得
		//圧縮対応
		Array< unsigned char > uncompressed;
		if ( data[ 2 ] & 0x8 ){ //圧縮してやがります。
			const unsigned char* s = src;
			const unsigned char* sEnd = reinterpret_cast< const unsigned char* >( data ) + size;
			uncompressed.setSize( pixelSize * sw * sh );
			int n = 0;
			while ( s < sEnd ){
				int l = ( *s & 0x7f ) + 1;
				bool compressed = ( ( *s & 0x80 ) != 0 );
				if ( n + l > sw * sh ){ //書き込み範囲チェック
					cout << "readTGA : can't read. compressed data is invalid." << endl;
					mIsError = true;
					return;
				}
				int readSize = pixelSize * ( ( compressed ) ? 1 : l );
				if ( s + readSize > sEnd ){ //ファイル末尾を越える。異常
					cout << "readTGA : can't read. compressed data is invalid. it must be truncated." << endl;
					mIsError = true;
					return;
				}
				++s;
				if ( compressed ){
					for ( int i = 0; i < l; ++i ){
						for ( int j = 0; j < pixelSize; ++j ){
							uncompressed[ n * pixelSize + j ] = s[ j ];
						}
						++n;
					}
					s += pixelSize;
				}else{
					for ( int i = 0; i < l; ++i ){
						for ( int j = 0; j < pixelSize; ++j ){
							uncompressed[ n * pixelSize + j ] = *s;
							++s;
						}
						++n;
					}
				}
				if ( n == sw * sh ){ //読み終わり
					break;
				}
			}
			src = &uncompressed[ 0 ]; //データポインタ差し替え
		} else if ( size < ( sh * sw * pixelSize + 18 + paletteNumber + paletteDepth ) ){
			//非圧縮ならファイルサイズの下限が存在する。
			cout << "readTGA : file must be collapsed." << endl;
			mIsError = true; //ファイルが壊れてる
			return;
		}
		//Y反転対応
		int yBegin;
		int yEnd;
		int dy;
		int dSrc;
		if ( ( data[ 0x11 ] & 0x20 ) == 0 ){
			yBegin = sh - 1;
			yEnd = -1;
			dy = -1;
			dSrc = -sw * pixelSize;
			src += sw * pixelSize * ( sh - 1 ); //後ろから始めないと
		} else {
			yBegin = 0;
			yEnd = sh;
			dy = 1;
			dSrc = sw * pixelSize;
		}
		//非対応型チェック
		if ( ( data[ 2 ] & 0x7 ) == 0 ){
			cout << "readTGA : this file contains no image." << endl;
			mIsError = true;
			return;
		}
		//2べきに直してテクスチャ作成
		int dh = powOfTwo( sh );
		int dw = powOfTwo( sw );
		createObject( dw, dh, true );

		//ロックして書き込み
		unsigned* surface;
		int pitch;
		lock( &surface, &pitch, 0 );
		pitch /= 4;
		unsigned* dst = surface;

		if ( pixelSize == 4 ){
			for ( int y = yBegin; y != yEnd; y += dy ){
				for ( int x = 0; x < sw; ++x ){
					// BGRA -> RGBA
					dst[ x ] = src[ x * 4 + 0 ] << 16;
					dst[ x ] |= src[ x * 4 + 1 ] << 8;
					dst[ x ] |= src[ x * 4 + 2 ];
					dst[ x ] |= src[ x * 4 + 3 ] << 24;
				}
				for ( int x = sw; x < pitch / 4; ++x ){ //Xあまりは真っ黒
					dst[ x ] = 0;
				}
				dst += pitch;
				src += dSrc;
			}
		} else if ( pixelSize == 3 ){
			for ( int y = yBegin; y != yEnd; y += dy ){
				for ( int x = 0; x < sw; ++x ){
					// BGR -> RGB
					dst[ x ] = src[ x * 3 + 0 ] << 16;
					dst[ x ] |= src[ x * 3 + 1 ] << 8;
					dst[ x ] |= src[ x * 3 + 2 ];
					dst[ x ] |= 0xff000000; //Aは255
				}
				for ( int x = sw; x < pitch; ++x ){ //Xあまりは真っ黒
					dst[ x ] = 0;
				}
				dst += pitch;
				src += dSrc;
			}
		} else if ( pixelSize == 2 ){ //グレイスケール+アルファ
			for ( int y = yBegin; y != yEnd; y += dy ){
				for ( int x = 0; x < sw; ++x ){
					unsigned t = src[ x * 2 + 0 ];
					dst[ x ] = t | ( t << 8 ) | ( t << 16 );
					dst[ x ] |= src[ x * 2 + 1 ] << 24;
				}
				for ( int x = sw; x < pitch; ++x ){ //Xあまりは真っ黒
					dst[ x ] = 0;
				}
				dst += pitch;
				src += dSrc;
			}
		} else if ( pixelSize == 1 ){
			if ( paletteNumber > 0 ){ //パレットある場合
				Array< unsigned > palette( paletteNumber );
				if ( paletteDepth == 3 ){
					for ( int i = 0; i < paletteNumber; ++i ){
						// BGR -> RGB
						palette[ i ] = pSrc[ i * 3 + 0 ] << 16;
						palette[ i ] |= pSrc[ i * 3 + 1 ] << 8;
						palette[ i ] |= pSrc[ i * 3 + 2 ];
						palette[ i ] |= 0xff000000; //Aは255
					}
				}else if ( paletteDepth == 4 ){
					for ( int i = 0; i < paletteNumber; ++i ){
						// BGRA => RGBA
						palette[ i ] = pSrc[ i * 4 + 0 ] << 16;
						palette[ i ] |= pSrc[ i * 4 + 1 ] << 8;
						palette[ i ] |= pSrc[ i * 4 + 2 ];
						palette[ i ] |= pSrc[ i * 4 + 3 ] << 24;
					}
				}
				for ( int y = yBegin; y != yEnd; y += dy ){
					for ( int x = 0; x < sw; ++x ){
						dst[ x ] = palette[ src[ x ] ];
					}
					for ( int x = sw; x < pitch; ++x ){ //Xあまりは真っ黒
						dst[ x ] = 0;
					}
					dst += pitch;
					src += dSrc;
				}
			} else {
				for ( int y = yBegin; y != yEnd; y += dy ){
					for ( int x = 0; x < sw; ++x ){
						// ARGB -> RGBA
						dst[ x ] = 0x00ffffff;
						dst[ x ] |= src[ x ] << 24;
					}
					for ( int x = sw; x < pitch; ++x ){ //Xあまりは真っ黒
						dst[ x ] = 0;
					}
					dst += pitch;
					src += dSrc;
				}
			}
		}
		//Yあまりを真っ黒に
		for ( int y = sh; y < dh; ++y ){
			for ( int x = 0; x < pitch; ++x ){
				dst[ x ] = 0;
			}
			dst += pitch;
		}
		createMipmapChain( surface, pitch, dw, dh, 1 );
		unlock( 0 );
		src = 0;
		dst = 0;
	}

	/// オブジェクト生成
	void createObject( GLint w, GLint h, bool createMipChain ) {
		glGenTextures( 1, &mObject );
		glBindTexture( GL_TEXTURE_2D, mObject );
		if ( createMipChain ) {
			// 完全なミップマップチェーンの生成
			int tw = w;
			int th = h;
			int level = 0;
			while ( ( tw > 0 ) || ( th > 0 ) ) {
				if ( tw == 0 ) {
					tw = 1;
				}
				if ( th == 0 ) {
					th = 1;
				}
				glTexImage2D( GL_TEXTURE_2D, level, GL_RGBA, tw, th, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0 );
				tw >>= 1;
				th >>= 1;
				++level;
			}
			mSurfaces.setSize( level );
		} else {
			glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0 );
			mSurfaces.setSize( 1 );
		}
		// 変更しないフィルタリングステートの設定
#if 0
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
#else
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
#endif
		glBindTexture( GL_TEXTURE_2D, 0 );
		// バッファ成功してから代入
		mWidth = w;
		mHeight = h;
	}

	/// 面倒なので再帰呼び出し。pitchはDWORD単位。つまり/4
	void createMipmapChain( const unsigned* src, int srcPitch, int sw, int sh, int level ) {
		int dw = sw >> 1;
		int dh = sh >> 1;
		if ( dw == 0 && dh == 0 ) { // 両方が0になった
			return;
		}
		if ( dw == 0 ) {
			dw = 1;
			srcPitch = 1;
		}
		if ( dh == 0 ) {
			dh = 1;
			srcPitch = 1;
		}
		unsigned* dstSurface;
		int dstPitch;
		lock( &dstSurface, &dstPitch, level );
		unsigned* dst = dstSurface;
		dstPitch /= 4;
		ASSERT( dstPitch >= dw ); //ここが小さいのはありえない。
		//とりあえず遅くてもいいや。
		for ( int y = 0; y < dh; ++y ) {
			for ( int x = 0; x < dw; ++x ) {
				// ボックスフィルタを使う。4pixelsの補完値を新しい値とする
				unsigned c0 = src[ ( 2 * x ) ];
				unsigned c1 = src[ ( 2 * x ) + 1 ];
				unsigned c2 = src[ ( 2 * x ) + srcPitch ];
				unsigned c3 = src[ ( 2 * x ) + srcPitch + 1 ];
				unsigned r = ( c0 & 0xff ) + ( c1 & 0xff ) + ( c2 & 0xff ) + ( c3 & 0xff );
				c0 >>= 8; c1 >>= 8; c2 >>= 8; c3 >>= 8;
				unsigned g = ( c0 & 0xff ) + ( c1 & 0xff ) + ( c2 & 0xff ) + ( c3 & 0xff );
				c0 >>= 8; c1 >>= 8; c2 >>= 8; c3 >>= 8;
				unsigned b = ( c0 & 0xff ) + ( c1 & 0xff ) + ( c2 & 0xff ) + ( c3 & 0xff );
				c0 >>= 8; c1 >>= 8; c2 >>= 8; c3 >>= 8;
				unsigned a = ( c0 & 0xff ) + ( c1 & 0xff ) + ( c2 & 0xff ) + ( c3 & 0xff );
				r = ( r + 2 ) >> 2; //四捨五入のために+2
				g = ( g + 2 ) >> 2; //四捨五入のために+2
				b = ( b + 2 ) >> 2; //四捨五入のために+2
				a = ( a + 2 ) >> 2; //四捨五入のために+2
				dst[ x ] = r | ( g << 8 ) | ( b << 16 ) | ( a << 24 );
			}
			dst += dstPitch;
			src += srcPitch * 2; //2行進む
		}
		//再帰呼び出し
		createMipmapChain( dstSurface, dstPitch, dw, dh, level + 1 );
		unlock( level );
	}

	/// 拡張子取得
	static Extension getExtension( const char* filename ) {
		int l = static_cast< int >( strlen( filename ) );
		Array< char > name( l );
		for ( int i = 0; i < l; ++i ) {
			name[ i ] = static_cast< char >( tolower( filename[ i ] ) );
		}
		Extension r = EXT_UNKNOWN;
		if (
			( name[ l - 4 ] == '.' ) &&
			( name[ l - 3 ] == 't' ) &&
			( name[ l - 2 ] == 'g' ) &&
			( name[ l - 1 ] == 'a' )
		) {
			r = EXT_TGA;
		} else if (
			( name[ l - 4 ] == '.' ) &&
			( name[ l - 3 ] == 'd' ) &&
			( name[ l - 2 ] == 'd' ) &&
			( name[ l - 1 ] == 's' )
		) {
			r = EXT_DDS;
		}
		return r;
	}
	/// unsigned に変換
	static unsigned int toUInt( const char* p ){
		const Byte* data = reinterpret_cast< const Byte* >( p );
		unsigned int ret = data[ 0 ];
		ret |= ( data[ 1 ] << 8 );
		ret |= ( data[ 2 ] << 16 );
		ret |= ( data[ 3 ] << 24 );
		return ret;
	}
	/// unsigned short に変換
	static unsigned short toUShort( const char* data ){
		const unsigned char* up = reinterpret_cast< const unsigned char* >( data );
		unsigned short r = up[ 0 ];
		r |= ( up[ 1 ] << 8 );
		return r;
	}
	/// unsigned char に変換
	static unsigned char toUChar( const char* data ){
		const unsigned char* up = reinterpret_cast< const unsigned char* >( data );
		return up[ 0 ];
	}
	/// 2のべき乗を求める
	static int powOfTwo( int a ) {
		ASSERT( a < 0x40000000 ); // これを2乗すると負の数になってまう
		int ret = 1;
		while ( ret < a ) {
			ret <<= 1;
		}
		return ret;
	}

	///サーフェイスっぽいサーフェイス保持用
	struct Surface {
		Surface() : mBuffer( 0 ), mX( 0 ), mY( 0 ), mW( 0 ), mH( 0 ) { }
		~Surface() {
			release();
		}
		void set( int x, int y, int w, int h ) {
			mX = x;
			mY = y;
			mW = w;
			mH = h;
			mBuffer = NEW unsigned[ mW * mH ];
		}
		void release() {
			SAFE_DELETE_ARRAY( mBuffer );
		}
		unsigned* mBuffer;
		int mX;
		int mY;
		int mW;
		int mH;
	};

	GLuint mObject;
	GLint mWidth;
	GLint mHeight;
	GLint mOriginalWidth;
	GLint mOriginalHeight;
	FileIO::InFile mFile;
	Array< Surface > mSurfaces;
	bool mIsError;
	Extension mExtension;
	char* mName;
};

} // namespace Graphics
} // namespace NTEngine

#endif // INCLUDED_NTENGINE_GRAPHICS_TEXTUREIMPL_H
